package reflectdemo1;

import java.lang.reflect.*;

//      优点
//        1. 对于任意一个类，都能够知道这个类的所有属性和方法；对于任意一个对象，都能够调用它的任意一个方法
//        2. 增加程序的灵活性和扩展性，降低耦合性，提高自适应能力
//        3. 反射已经运用在了很多流行框架如：Struts、Hibernate、Spring 等等。
//      缺点
//        1. 使用反射会有效率问题。会导致程序效率降低。
//        2. 反射技术绕过了源代码的技术，因而会带来维护问题。反射代码比相应的直接代码更复杂 。


//              反射中几个重要的类   Class  Field  Method  Constructor
//                   在哪里用到反射  框架 哪里 怎么用
//  反射的使用
public class ReflectClassDemo {
    /**
     * 创建对象
     * 通过Class类的newInstance方法 获取学生实例
     */
    public static void reflectNewInstance(){
        try {
            Class<?> c1 = Class.forName("reflectdemo1.Student");

//            获取对象
            Student student = (Student)c1.newInstance();

            System.out.println(student);

            student.sleep();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }


    // 反射私有的构造方法 屏蔽内容为获得公有的构造方法
    public static void reflectPrivateConstructor() {
        try {
            Class<?> c1 = Class.forName("reflectdemo1.Student");
//            获得该类中与参数类型匹配的构造方法  私有的和公有的都可以获取
//            这里演示获取私有的构造方法
            Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class);
//            getDeclaredConstructor查看源码发现传入   (Class<?>... parameterTypes)类型
//                                              ...表示泛型        parameterTypes传入参数的类型
//                                                  构造方法 有一个String类型和int类型
//            getDeclaredConstructor的返回类型是Constructor<T>

            constructor.setAccessible(true);
            //表示constructor是可改变的 如果没有下面两行代码会报错
            //如果不是私有的可以不调用setAccessible  私有想要改变就需要调用


            Student student = (Student)constructor.newInstance("cat",18);
            System.out.println(student);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }




    // 反射私有属性
    public static void reflectPrivateField() {
        try {
            Class<?> c1 = Class.forName("reflectdemo1.Student");

            Student student = (Student)c1.newInstance();

            Field field = c1.getDeclaredField("name");
            field.setAccessible(true);

            field.set(student,"dog");
            System.out.println(student);


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }




    // 反射私有方法
    public static void reflectPrivateMethod() {
        try {
            Class<?> c1 = Class.forName("reflectdemo1.Student");

            Student student = (Student)c1.newInstance();

            Method method = c1.getDeclaredMethod("function", String.class);
//                                                   方法名称           方法参数
            method.setAccessible(true);
            method.invoke(student,"我是私有的参数");


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        reflectNewInstance();
//        打印
//        Student()     这里是newInstance()打印Student类不带参数的构造方法
//        Student{name='bit', age=18}
//        i am pig

        reflectPrivateConstructor();
//        Student(String,name)
//        Student{name='cat', age=18}

        reflectPrivateField();
//        Student()
//        Student{name='dog', age=18}

        reflectPrivateMethod();
//        Student()
//        我是私有的参数
    }
}
